package com.ricervcvcer.goods.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ricervcvcer.common.util.RicervcvcerConstant;
import com.ricervcvcer.goods.client.BrandClient;
import com.ricervcvcer.goods.client.CategoryClient;
import com.ricervcvcer.goods.emun.ESEnum;
import com.ricervcvcer.goods.entity.*;
import com.ricervcvcer.goods.mapper.TbSpuMapper;
import com.ricervcvcer.goods.service.*;
import com.ricervcvcer.goods.util.EsConst;
import com.ricervcvcer.goods.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * spu表，该表描述的是一个抽象性的商品，比如 iphone8 服务实现类
 * </p>
 *
 * @author moge
 * @since 2022-01-06
 */
@Slf4j
@Service
public class TbSpuServiceImpl extends ServiceImpl<TbSpuMapper, TbSpu> implements ITbSpuService {

    @Autowired
    CategoryClient categoryClient;

    @Autowired
    BrandClient brandClient;

    @Autowired
    ITbSkuService skuService;

    @Autowired
    ITbSpuDetailService spuDetailService;

    @Autowired
    private RestHighLevelClient client;

    @Autowired
    ITbSpecParamService specParamService;

    @Autowired
    ITbStockService stockService;

    @Override
    public boolean addSpuEST() {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("100s");

        List<TbSpu> tbSpus = this.baseMapper.selectList(null);
        // 进行查询数据封装
        List<GoodsCategoryBrandVO> collect = tbSpus.stream().map(item -> {
            GoodsCategoryBrandVO goodsCategoryBrandVO = new GoodsCategoryBrandVO();
            BeanUtils.copyProperties(item, goodsCategoryBrandVO);

            // 查询分类信息
            TbCategory category = categoryClient.getById(item.getCid3()).getData();
            goodsCategoryBrandVO.setCName(category.getName());

            // 查询品牌信息
            TbBrand body = brandClient.getBrandById(item.getBrandId()).getBody();
            goodsCategoryBrandVO.setBrandName(body.getName());

            // 返回
            return goodsCategoryBrandVO;
        }).collect(Collectors.toList());

        // 批处理请求
        for (int i = 0; i < collect.size(); i++) {
            // 批量添加
            bulkRequest.add(new IndexRequest(EsConst.ES_INDEX_SPU).
                    id(collect.get(i).getId().toString())
                    .source(JSON.toJSONString(collect.get(i)), XContentType.JSON));
        }

        BulkResponse bulkResponse = null;
        try {
            bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(bulkResponse.hasFailures()){
            throw new RuntimeException(ESEnum.ES_BULK_ERROR.getMsg());
        }
        return true;
    }

//    @Cacheable(cacheNames = {"spu"},key = "'getSpu'")
//    @Override
//    public Page<GoodsCategoryBrandVO> getSpu(String spuName, Integer page, Integer rows) {
//        Page<TbSpu> page1 = new Page(page, rows);
//        QueryWrapper<TbSpu> qw=new QueryWrapper();
//        if(!StringUtils.isEmpty(spuName)){
//            qw.eq("title",spuName);
//        }
//
//        page1 = this.baseMapper.selectPage(page1, qw);
//
//        // 进行查询数据封装
//        Page<GoodsCategoryBrandVO> gcbPage = new Page(page, rows);
//
//        List<TbSpu> records = page1.getRecords();
//        gcbPage.setRecords(records.stream().map(item->{
//            GoodsCategoryBrandVO goodsCategoryBrandVO = new GoodsCategoryBrandVO();
//            BeanUtils.copyProperties(item,goodsCategoryBrandVO);
//
//            // 查询分类信息
//            TbCategory category  = categoryClient.getById(item.getCid3()).getData();
//            goodsCategoryBrandVO.setCName(category.getName());
//
//            // 查询品牌信息
//            TbBrand body = brandClient.getBrandById(item.getBrandId()).getBody();
//            goodsCategoryBrandVO.setBrandName(body.getName());
//
//            // 查询对应spu中的sku属性
//            convet(goodsCategoryBrandVO);
//            // 返回
//            return  goodsCategoryBrandVO;
//        }).collect(Collectors.toList()));
//
//        // 查询商品对应分类
//        return gcbPage;
//    }

    @Override
    public SpuParamVO selectJoin(Long id) {
        // 根据id 查询sku
        TbSpu tbSpu = this.baseMapper.selectById(id);

        // 查询sku详细信息
        QueryWrapper qw=new QueryWrapper();
        qw.eq("spu_id",id);
        TbSpuDetail tbSpuDetail = (TbSpuDetail) spuDetailService.list(qw).get(0);

        // 获取spu规格参数
        Map<String,Object> map = JSONObject.parseObject(tbSpuDetail.getGenericSpec(), Map.class);

        // 分装成对象集合
        List<SpecParamVO> specParamVOS = getSpecParamVOS(map);

        // cope对象
        SpuParamVO spuParamVO=new SpuParamVO();
        BeanUtils.copyProperties(tbSpu,spuParamVO);

        // 设置 spu详情
        spuParamVO.setSpecParamVOList(specParamVOS);
        spuParamVO.setSpuDetail(tbSpuDetail);
        return spuParamVO;
    }

    @Transactional
    @Override
    public void editSpu(SpuParamVO sp) {
        // 提取数据
        TbSpuDetail spuDetail = sp.getSpuDetail();                      // 详情

        List<SpecParamVO> specParamVOList = sp.getSpecParamVOList();    // 规格
        TbSpu tbSpu=new TbSpu();

        BeanUtils.copyProperties(sp,tbSpu);                             // 基本
        tbSpu.setLastUpdateTime(LocalDateTime.now());

        // 重新封装spu的通用属性
        Map<String, Object> collect = specParamVOList.stream()
                .collect(Collectors.toMap(param -> param.getId().toString(), param -> param.getValue()));

        spuDetail.setGenericSpec(JSONObject.toJSONString(collect));

        // 修改
        boolean spuStatus = this.updateById(tbSpu);

        QueryWrapper qw=new QueryWrapper();
        qw.eq("spu_id",spuDetail.getSpuId());
        boolean spuDetailStatus = spuDetailService.update(spuDetail, qw);

        if(!(spuStatus && spuDetailStatus)) {
            throw new RuntimeException(RicervcvcerConstant.UPDATE_ERROR);
        }

        // 修改ES
        UpdateRequest updateRequest = new UpdateRequest(EsConst.ES_INDEX_SPU, String.valueOf(tbSpu.getId()));
        updateRequest.timeout("1s");

        updateRequest.doc(JSON.toJSONString(tbSpu), XContentType.JSON);

        try {
            UpdateResponse update = client.update(updateRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(RicervcvcerConstant.UPDATE_ERROR);
        }

    }

    @Override
    public Page<GoodsCategoryBrandVO> getSpu(String spuName, Integer page, Integer rows, boolean searchSaleable) {
        // 基本条件的搜索
        SearchRequest searchRequest = new SearchRequest(EsConst.ES_INDEX_SPU);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 分页
        sourceBuilder.size(rows).from(page);

        // 精确匹配 QueryBuilders 根据自己的要求配置查询体条件即可
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (spuName != "") {
            boolQueryBuilder.must(QueryBuilders.matchQuery("title",spuName));
            // 配置搜索信息
//            boolQueryBuilder.must(QueryBuilders.matchQuery("saleable",searchSaleable));
        }
        // 匹配上架/下架
        boolQueryBuilder.filter(QueryBuilders.termQuery("saleable",searchSaleable));
        sourceBuilder.query(boolQueryBuilder);

        sourceBuilder.timeout(TimeValue.timeValueSeconds(60));
        sourceBuilder.trackTotalHits(true);
        sourceBuilder.sort("id",SortOrder.ASC);

        // 搜索
        searchRequest.source(sourceBuilder);
        SearchResponse search = null;
        try {
            search = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Page<GoodsCategoryBrandVO> gcbPage = new Page(page, rows);
        List<GoodsCategoryBrandVO> goodsCategoryBrandVOList =new ArrayList<>();

        // 解析结果
        for (SearchHit hit : search.getHits().getHits()) {
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            goodsCategoryBrandVOList.add(JSON.parseObject(JSON.toJSONString(sourceAsMap),GoodsCategoryBrandVO.class));
        }
        System.out.println("-------->"+sourceBuilder.toString());
        gcbPage.setRecords(goodsCategoryBrandVOList);
        final TotalHits totalHits = search.getHits().getTotalHits();
        gcbPage.setTotal(totalHits.value);
        // 查询商品对应分类
        return gcbPage;
    }

    @Override
    public List<SkuParamVO> getSkuBySpuId(Long spu_id) {
        // 基本条件的搜索
        SearchRequest searchRequest = new SearchRequest(EsConst.ES_INDEX_SKU);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 精确匹配 QueryBuilders 根据自己的要求配置查询体条件即可
        TermQueryBuilder termQuery = QueryBuilders.termQuery("spuId", spu_id);

        // 配置搜索信息z
        sourceBuilder.query(termQuery);
        sourceBuilder.timeout(TimeValue.timeValueSeconds(60));
        sourceBuilder.sort("id", SortOrder.ASC);

        // 搜索
        searchRequest.source(sourceBuilder);
        SearchResponse search = null;
        try {
            search = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 解析结果
        List<SkuParamVO> skuParamVOList = new ArrayList<>();
        for (SearchHit hit : search.getHits().getHits()) {
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            SkuParamVO skuParamVO = JSON.parseObject(JSON.toJSONString(sourceAsMap),SkuParamVO.class);
            skuParamVOList.add(skuParamVO);
        }
        return skuParamVOList;
    }

    @Override
    public void create(SpecSpuSkuVO obj) {
        List<Map<String,Object>> skuList = obj.getSkuList(); // sku数据列表
        TbSpu spu = obj.getSpu();   // 商品基本信息
        TbSpuDetail spuDetail = obj.getSpuDetail(); // 商品详细信息
        List<Long> cids = obj.getCids(); // 分类id

        // 设置分类id ，创建时间
        spu.setCid1(cids.get(0));
        spu.setCid2(cids.get(1));
        spu.setCid3(cids.get(2));

        spu.setCreateTime(LocalDateTime.now());

        // 添加spu
        boolean spuStatus = this.saveOrUpdate(spu);
        // 添加spu详情
        spuDetail.setSpuId(spu.getId());
        boolean spuDetailStatus = spuDetailService.save(spuDetail);

        // SKU 集合
        List<SkuParamVO> skuParamVOS =new ArrayList<>();
        // 添加循环添加sku
        for (Map<String,Object> item :skuList) {
            if(Objects.isNull(item)){
                continue;
            }
            TbSku tbSku = new TbSku();
            tbSku.setSpuId(spu.getId());
            tbSku.setTitle(spu.getTitle());
            double d = Double.parseDouble(item.get("price").toString());
            long price = (long)d*100;
            tbSku.setPrice( price);
            tbSku.setEnable(false);
            tbSku.setCreateTime(LocalDateTime.now());
            // TODO sku 排序 indexes设置
            // 提前获取库存
            int stock = Integer.parseInt(item.get("stock").toString());
            // 从item中移除price stock
            item.remove("price");
            item.remove("stock");
            tbSku.setOwnSpec(JSON.toJSONString(item));

            // 添加sku
            boolean skuStatus = skuService.saveOrUpdate(tbSku);

            // 添加到集合
            SkuParamVO skuParamVO = new SkuParamVO();
            BeanUtils.copyProperties(tbSku,skuParamVO);
            List<SpecParamVO> specParamVOList =new ArrayList<>();

            for(String key: item.keySet()){
                //keySet获取map集合key的集合  然后在遍历key即可
                SpecParamVO spvo=new SpecParamVO();
                TbSpecParam specParam = specParamService.getById(key);
                BeanUtils.copyProperties(specParam,spvo);
                spvo.setValue(item.get(key));
                specParamVOList.add(spvo);
            }

            skuParamVO.setSpecParamVO(specParamVOList);
            skuParamVOS.add(skuParamVO);

            // 添加库存
            TbStock tbStock=new TbStock();
            tbStock.setSkuId(tbSku.getId());
            tbStock.setStock(stock);
            boolean stockStatus = stockService.save(tbStock);

            if(!skuStatus && !stockStatus){
                throw new RuntimeException(RicervcvcerConstant.ADD_ERROR);
            }
        }

        if(!spuStatus && !spuDetailStatus){
            throw new RuntimeException(RicervcvcerConstant.ADD_ERROR);
        }

        // 添加到SPU ES
        GoodsCategoryBrandVO goodsCategoryBrandVO = new GoodsCategoryBrandVO();
        BeanUtils.copyProperties(spu,goodsCategoryBrandVO);
        QueryWrapper queryWrapper=new QueryWrapper();
        queryWrapper.eq("spu_id",spu.getId());
        goodsCategoryBrandVO.setBrandName(brandClient.getBrandById(spu.getBrandId()).getBody().getName());
        goodsCategoryBrandVO.setCName(categoryClient.getById(spu.getCid3()).getData().getName());

        // 创建请求
        IndexRequest request = new IndexRequest(EsConst.ES_INDEX_SPU);

        // 规则 wlh_index/_doc/1
        request.id(String.valueOf(spu.getId()));
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("5s");

        // 将我们的数据放入请求 json
        request.source(JSON.toJSONString(goodsCategoryBrandVO), XContentType.JSON);

        // 客户端发送请求获取响应的接口
        try {
            IndexResponse index = client.index(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(RicervcvcerConstant.UPDATE_ERROR);
        }

        // 添加到SPU ES
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("100s");

        // 客户端发送请求获取响应的接口
        // 批处理请求
        for (int i = 0; i < skuParamVOS.size(); i++) {
            // 批量添加
            bulkRequest.add(new IndexRequest(EsConst.ES_INDEX_SKU).
                    id(skuParamVOS.get(i).getId().toString())
                    .source(JSON.toJSONString(skuParamVOS.get(i)),XContentType.JSON));
        }

        try {
            BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void addSkuEST() {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("100s");

        List<TbSku> tbSkus = skuService.list(null);

        // 进行查询数据封装
        List<SkuParamVO> collect = tbSkus.stream().map(item -> {
            SkuParamVO skuParamVO = new SkuParamVO();
            BeanUtils.copyProperties(item, skuParamVO);
            // 获取sku属性
            Map<String, Object> map = JSONObject.parseObject(item.getOwnSpec(), Map.class);

            // 当前sku的spu属性集合
            List<SpecParamVO> skuParamVOS = new ArrayList<>();

            for(String key: map.keySet()){
                //keySet获取map集合key的集合  然后在遍历key即可
                SpecParamVO spvo=new SpecParamVO();
                TbSpecParam specParam = specParamService.getById(key);
                BeanUtils.copyProperties(specParam,spvo);
                spvo.setValue(map.get(key));
                skuParamVOS.add(spvo);
            }
            skuParamVO.setSpecParamVO(skuParamVOS);
            return skuParamVO;
        }).collect(Collectors.toList());

        // 批处理请求
        for (int i = 0; i < collect.size(); i++) {
            // 批量添加
            bulkRequest.add(new IndexRequest(EsConst.ES_INDEX_SKU).
                    id(collect.get(i).getId().toString())
                    .source(JSON.toJSONString(collect.get(i)),XContentType.JSON));
        }

        BulkResponse bulkResponse = null;
        try {
            bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info(String.valueOf(bulkResponse.hasFailures()));
    }

    /**
     * 把sku分装到对应的spu中，以及销售属性
     * @param gcb
     */
    public void convet(GoodsCategoryBrandVO gcb){
        QueryWrapper qw = new QueryWrapper();
        qw.eq("spu_id", gcb.getId());
        List<TbSku> skus = skuService.list(qw);

        gcb.setSkuList(skus.stream().map(item -> {
            SkuParamVO skuParamVO=new SkuParamVO();
            BeanUtils.copyProperties(item,skuParamVO);
            // 获取sku属性
            Map<String,Object> map = JSONObject.parseObject(item.getOwnSpec(), Map.class);

            // 当前sku的spu属性集合
            List<SpecParamVO> skuParamVOS = getSpecParamVOS(map);
            skuParamVO.setSpecParamVO(skuParamVOS);
            return skuParamVO;
        }).collect(Collectors.toList()));
    }

    /**
     * 根据map中的SpecParam中的属性id分装到SpecParamVO
     * @param map
     * @return
     */
    private List<SpecParamVO> getSpecParamVOS(Map<String, Object> map) {
        // 创建存储sku属性集合
        List<SpecParamVO> skuParamVOS=new ArrayList<>();

        for(String key: map.keySet()){
            //keySet获取map集合key的集合  然后在遍历key即可
            SpecParamVO spvo=new SpecParamVO();
            TbSpecParam specParam = specParamService.getById(key);
            BeanUtils.copyProperties(specParam,spvo);
            spvo.setValue(map.get(key));
            skuParamVOS.add(spvo);
        }
        return skuParamVOS;
    }
}
